/**
 * @Date: Feb 19, 2010 1:18:42 PM
 */
package com.philip.journal.home.service;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.philip.journal.core.Constant;
import com.philip.journal.core.exception.JournalException;
import com.philip.journal.core.service.BaseService;
import com.philip.journal.home.bean.Branch;

/**
 * This class provides functionality for import/export of data to/from xml files.
 *
 * @author cry30
 */
public class ImportExportXmlServiceImpl extends BaseService implements ImportExportXmlService {

    /** XML Tag. RTFC. */
    public static final String YES = "yes";

    /** XML Tag. RTFC. */
    public static final String NO = "no"; // NOPMD by r39 on 3/30/11 1:56 PM

    /** XML Tag. RTFC. */
    public static final String INDENT_NO = "indent-number";

    /** XML Root Tag. */
    public static final String TAG_JOURNAL = "Journal";

    /** RTFC. */
    private static final long ROOT_ID = Constant.ROOT_ID;

    /** XPath for location of Branches under Root. */
    private static final String XPATH_ROOT_BRANCH = "/Journal/Branch/Branches/Branch";

    /** Helper class. */
    private transient XmlHelper xmlHelper;

    /** XML Transformer service. */
    private transient TransformerFactory transformFactory;

    /** Thread lock. */
    private static Object lock = new Object();

    @Override
    public void importCodeXML(final Map<String, Object> session, final InputStream xmlData)
    {
        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        try {
            final DocumentBuilder docBuilder = dbf.newDocumentBuilder();
            final Document document = docBuilder.parse(xmlData);
            final XPath xpath = XPathFactory.newInstance().newXPath();
            final NodeList nodes = (NodeList) xpath.evaluate(XPATH_ROOT_BRANCH, document,
                    XPathConstants.NODESET);

            for (int i = 0; nodes != null && i < nodes.getLength(); i++) {
                final Element branchElement = (Element) nodes.item(i);
                getXmlHelper().extractBranchFromDocument(branchElement, ROOT_ID);
            }

        } catch (final Exception exception) {
            throw new JournalException(exception.getMessage(), exception);
        }
    }

    @Override
    public void exportToXML(final Map<String, Object> session, final OutputStream targetStream)
    {
        final DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder;
        try {
            docBuilder = dbfac.newDocumentBuilder();
        } catch (final ParserConfigurationException e) {
            throw new JournalException(e.getMessage(), e);
        }
        final Document doc = docBuilder.newDocument();

        final Branch rootBranch = getDaoFacade().getBranchDAO().read(ROOT_ID);
        final Element rootElement = doc.createElement(TAG_JOURNAL);
        doc.appendChild(rootElement);
        getXmlHelper().convertNodeToXml(doc, rootElement, rootBranch);

        try {
            synchronized (lock) {
                final TransformerFactory locTransFactory = getTransformFactory();
                locTransFactory.setAttribute(INDENT_NO, INDENT_SIZE);
                final Transformer trans = locTransFactory.newTransformer();
                trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, NO);
                trans.setOutputProperty(OutputKeys.INDENT, YES);
                trans.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(targetStream, "UTF-8")));
            }
        } catch (final TransformerException e) {
            throw new JournalException(e.getMessage(), e);
        } catch (final UnsupportedEncodingException e) {
            throw new JournalException(e.getMessage(), e);
        }
    }

    public XmlHelper getXmlHelper() {
        return xmlHelper;
    }

    public void setXmlHelper(final XmlHelper pXmlpHelper) {
        this.xmlHelper = pXmlpHelper;
    }

    public TransformerFactory getTransformFactory() {
        return transformFactory;
    }

    public void setTransformFactory(final TransformerFactory pTransformFactory) {
        this.transformFactory = pTransformFactory;
    }

}
